#include "stdafx.h"
#include "vector.h"
#include "block.h"

/*
	//block type data
	const vec2 shape_I[BLOCK_SIZE][7]	=		{{0, 0},	{1, 0},		{2, 0},		{3, 0}};	//I
	const vec2 shape_LL[BLOCK_SIZE]		=		 {0, 0},	{1, 0},		{2, 0},		{2, -1}};	//L-left
	const vec2 shape_LR[BLOCK_SIZE]		=		 {0, 0},	{1, 0},		{2, 0},		{2, 1}};	//L-right
	const vec2 shape_ZL[BLOCK_SIZE]		=		 {0, 0},	{1, 0},		{1, -1},	{2, -1}};	//Z-left
	const vec2 shape_ZR[BLOCK_SIZE]		=		 {0, 0},	{1, 0},		{1, 1},		{2, 1}};	//Z-right
	const vec2 shape_E[BLOCK_SIZE]		=		 {0, 0},	{0, -1},	{0, 1},		{1, 0}};	//.:.
	const vec2 shape_O[BLOCK_SIZE]		=		 {0, 0},	{1, 0},		{1, 1},		{0, 1}};	//square
*/

block::block(vec2& pos, block_shape shape, block_color color)
	: color(color)
{
	this->pos = pos;

	switch (shape)
	{
	case SHAPE_I:
		offsets[0] = vec2(-1, 0); offsets[1] = vec2(0, 0); offsets[2] = vec2(1, 0); offsets[3] = vec2(2, 0);
		rotate_cycle = 2;
		break;
	case SHAPE_LL:
		offsets[0] = vec2(-1, 1); offsets[1] = vec2(0, 1); offsets[2] = vec2(1, 1); offsets[3] = vec2(1, 0);
		rotate_cycle = 4;
		break;
	case SHAPE_LR:
		offsets[0] = vec2(-1, -1); offsets[1] = vec2(0, -1); offsets[2] = vec2(1, -1); offsets[3] = vec2(1, 0);
		rotate_cycle = 4;
		break;
	case SHAPE_ZL:
		offsets[0] = vec2(-1, 0); offsets[1] = vec2(0, 0); offsets[2] = vec2(0, -1); offsets[3] = vec2(1, -1);
		rotate_cycle = 2;
		break;
	case SHAPE_ZR:
		offsets[0] = vec2(-1, 0); offsets[1] = vec2(0, 0); offsets[2] = vec2(0, 1); offsets[3] = vec2(1, 1);
		rotate_cycle = 2;
		break;
	case SHAPE_E:
		offsets[0] = vec2(-1, 0); offsets[1] = vec2(0, 0); offsets[2] = vec2(0, 1); offsets[3] = vec2(0, -1);
		rotate_cycle = 4;
		break;
	case SHAPE_O:
		offsets[0] = vec2(-1, 0); offsets[1] = vec2(0, 0); offsets[2] = vec2(0, 1); offsets[3] = vec2(-1, 1);
		rotate_cycle = 1;
		break;
	}

	for (int i = 0; i < BLOCK_SIZE; i++)
	{
		origin_offsets[i]	= offsets[i];
		points_able[i]		= true;
		points[i]			= pos + offsets[i];
		refine(points[i]);
	}

	delay_move		= vec2(0, 0);
	delay_rotate	= 0;
	current_rotate	= 0;
}

block::block(block& b)
	: color(b.color)
	, delay_rotate(b.delay_rotate)
	, rotate_cycle(b.rotate_cycle)
	,current_rotate(b.current_rotate)
{
	pos = b.pos;
	delay_move = b.delay_move;

	for (int i = 0; i < BLOCK_SIZE; i++)
	{
		offsets[i]			= b.offsets[i];
		origin_offsets[i]	= b.origin_offsets[i];
		points[i]			= b.points[i];
		points_able[i]		= b.points_able[i];
	}
}

block::~block()
{
}

void block::refine(vec2& point)
{
	if (point.y == GROUND_MAX_Y)
		point.y = 0;
	if (point.y == -1)
		point.y = GROUND_MAX_Y - 1;
}

void block::move(int x, int y)
{
	delay_move = delay_move + vec2(x, y);
}

bool block::update()
{
	if (delay_move == vec2(0, 0) && delay_rotate == 0) //no changes were made yet
		return false;
	else
	{
		//move
		if (delay_move != vec2(0, 0))
		{
			pos = pos + delay_move;
			refine(pos);
			delay_move = vec2(0, 0);
		}

		//rotate
		//the offsets[] is implemented like this:
		//	y		0						y		0
		//x +--+--+--+--+				  x +--+--+--+--+			
		//	|  |  |* |	|					|  |  |* |	|
		//	+--+--+--+--+					+--+--+--+--+
		//0	|  |* |* |* |		rotate	  0	|  |  |* |* |
		//	+--+--+--+--+		 ==>		+--+--+--+--+	
		//	|  |  |  |	|					|  |  |* |	|
		//	+--+--+--+--+					+--+--+--+--+
		//	|  |  |  |	|					|  |  |  |	|
		//	+--+--+--+--+					+--+--+--+--+
		//
		//That is E-type block. When we rotate (right) we will do it around (0, 0)
		//and the algorithms is that:
		//		new_offset.x = offsets[i].y;
		//		new_offset.y = -offsets[i].x;
		//

		if (delay_rotate > 0)
		{
			current_rotate = (current_rotate + delay_rotate) % rotate_cycle;
			delay_rotate = 0;

			for (int i = 0; i < BLOCK_SIZE; i++)
				offsets[i] = origin_offsets[i];

			for (int i = 0; i < current_rotate; i++)
			{
				vec2 new_offset;
				for (int i = 0; i < BLOCK_SIZE; i++)
				{
					new_offset.x = offsets[i].y;
					new_offset.y = -offsets[i].x;
					offsets[i] = new_offset;
				}
			}
		}

		//update points[]
		for (int i = 0; i < BLOCK_SIZE; i++)
		{
			if (points_able[i])
			{
				points[i] = pos + offsets[i];
				refine(points[i]);
			}
		}

		return true;
	}
}

void block::rotate_preview()
{
	current_rotate = (current_rotate + 1) % rotate_cycle;

	for (int i = 0; i < BLOCK_SIZE; i++)
		offsets[i] = origin_offsets[i];

	for (int i = 0; i < current_rotate; i++)
	{
		vec2 new_offset;
		for (int i = 0; i < BLOCK_SIZE; i++)
		{
			new_offset.x = offsets[i].y;
			new_offset.y = -offsets[i].x;
			offsets[i] = new_offset;
		}
	}

	//update points[]
	for (int i = 0; i < BLOCK_SIZE; i++)
	{
		if (points_able[i])
		{
			points[i] = pos + offsets[i];
			refine(points[i]);
		}
	}
}

void block::rotate()
{
	delay_rotate++;
}

bool block::contains(vec2& point)
{
	bool ret = false;
	for (int i = 0; i < BLOCK_SIZE; i++)
		ret = ret || (points[i] == point && points_able[i]);

	return ret;
}

//return true if all points disabled, which means block will be removed
bool block::remove_point(int x, int y)
{
	bool ret = false;

	for (int i = 0; i < BLOCK_SIZE; i++)
	{
		if (points[i] == vec2(x, y))
			points_able[i] = false;
		ret = ret || points_able[i];
	}
	return (!ret);
}